"""
API基础数据模型

定义简洁的API数据模型和响应格式
"""

from typing import List, Optional, Any, TypeVar, Generic, get_origin, get_args, Union
from pydantic import BaseModel, Field, ConfigDict
from datetime import datetime
import logging
import json

from axiom_boot.core.types import BigInt


T = TypeVar('T')
logger = logging.getLogger(__name__)


class ApiModel(BaseModel):
    """API基础模型，提供统一的配置和功能扩展"""
    
    model_config = ConfigDict(
        from_attributes=True,  # 支持ORM模型转换
        json_encoders={
            datetime: lambda dt: dt.isoformat()  # 格式化日期时间
        },
        arbitrary_types_allowed=True  # 允许模型字段为任意类型
    )

    @classmethod
    def model_validate(
        cls,
        obj: Any,
        *,
        strict: bool | None = None,
        from_attributes: bool | None = None,
        context: dict[str, Any] | None = None,
    ):
        """
        重写核心验证方法，以确保在验证前可靠地进行ID转换和JSON反序列化。
        此版本通过“递归清洗”模式解决 `from_attributes` 导致的上下文冲突问题。
        """
        # 步骤1: 检查输入是否为需要特殊处理的ORM对象。
        if hasattr(obj, '_sa_instance_state'):
            
            def _is_str_target(annotation: Any) -> bool:
                """
                辅助函数，健壮地检查类型注解是否为 str 或 Optional[str]。
                能同时处理 typing.Union 和新的 | 语法。
                """
                import types
                from typing import Union, get_origin, get_args

                origin = get_origin(annotation)
                if origin is Union or origin is types.UnionType:
                    return str in get_args(annotation)
                return annotation is str

            def _is_dict_target(annotation: Any) -> bool:
                """
                [新增] 辅助函数，健壮地检查类型注解是否为 dict 或 Optional[dict]。
                """
                import types
                from typing import Dict, Union, get_origin, get_args

                origin = get_origin(annotation)
                if origin is Union or origin is types.UnionType:
                    return any(get_origin(arg) in (dict, Dict) for arg in get_args(annotation))
                return get_origin(annotation) in (dict, Dict)

            # 步骤2: 手动将ORM对象转换为字典，并在过程中进行智能类型转换。
            dict_data = {}
            for field_name, field_info in cls.model_fields.items():
                if hasattr(obj, field_name):
                    source_value = getattr(obj, field_name)

                    # 2a: 处理 ID (int -> str) 的转换
                    if _is_str_target(field_info.annotation) and isinstance(source_value, int):
                        dict_data[field_name] = str(source_value)
                        continue

                    # 2b: [新增] 处理 JSON 字段 (str -> dict) 的自动反序列化
                    if _is_dict_target(field_info.annotation) and isinstance(source_value, str):
                        try:
                            dict_data[field_name] = json.loads(source_value)
                            continue
                        except (json.JSONDecodeError, TypeError):
                            # 如果解析失败，则传递原始值让 Pydantic 报告更具体的错误
                            pass
                    
                    # 2c: 默认情况，直接赋值
                    dict_data[field_name] = source_value
            
            # 步骤3: 【关键】用清洗好的字典递归调用本方法，并强制 from_attributes=False。
            return cls.model_validate(
                dict_data, strict=strict, from_attributes=False, context=context
            )
        
        # 对于所有其他情况（包括上面递归调用传入的字典），直接使用Pydantic的原生验证流程。
        return super().model_validate(
            obj, strict=strict, from_attributes=from_attributes, context=context
        )


class ApiResponse(ApiModel, Generic[T]):
    """全局API响应包装器
    
    用于统一包装所有API响应格式
    
    泛型参数:
        T: 响应数据类型
    """
    data: Optional[T] = Field(
        default=None, 
        description="响应数据",
        title="响应数据"
    )
    code: int = Field(
        default=200, 
        description="状态码",
        title="状态码"
    )
    message: str = Field(
        default="操作成功", 
        description="响应消息",
        title="响应消息"
    )
    success: bool = Field(
        default=True, 
        description="是否成功",
        title="是否成功"
    )
    
    @classmethod
    def ok(cls, data: T = None, message: str = "操作成功", code: int = 200):
        """创建成功响应"""
        return cls(
            data=data,
            message=message,
            code=code,
            success=True
        )
    
    @classmethod
    def fail(cls, message: str = "操作失败", code: int = 500, data: T = None):
        """创建错误响应"""
        return cls(
            data=data,
            message=message,
            code=code,
            success=False
        )


class PaginationParams(ApiModel):
    """分页参数基础模型"""
    page: int = Field(1, description="页码", ge=1)
    page_size: int = Field(20, description="每页数量", ge=1, le=100)


class FilterParams(ApiModel):
    """基础过滤参数模型"""
    
    def to_filter_dict(self) -> dict:
        """转换为过滤条件字典"""
        return {k: v for k, v in self.model_dump().items() if v is not None}


class PaginatedResponse(ApiModel, Generic[T]):
    """分页响应模型"""
    items: List[T] = Field(default_factory=list, description="数据列表")
    total: int = Field(0, description="总数量")
    page: int = Field(1, description="当前页码")
    page_size: int = Field(20, description="每页数量")
    total_pages: int = Field(0, description="总页数")
    
    @classmethod
    def create(cls, items: List[T], total: int, page: int, page_size: int):
        """创建分页响应"""
        total_pages = (total + page_size - 1) // page_size
        return cls(
            items=items,
            total=total,
            page=page,
            page_size=page_size,
            total_pages=total_pages
        )


# 便捷的响应创建函数
def success_response(data: Any = None, message: str = "操作成功", code: int = 200) -> ApiResponse:
    """创建成功响应"""
    return ApiResponse.ok(data=data, message=message, code=code)


def error_response(message: str = "操作失败", code: int = 500, data: Any = None) -> ApiResponse:
    """创建错误响应"""
    return ApiResponse.fail(message=message, code=code, data=data)


def paginated_response(items: List[Any], total: int, page: int, page_size: int) -> PaginatedResponse:
    """创建分页响应"""
    return PaginatedResponse.create(items=items, total=total, page=page, page_size=page_size) 